import { Op } from 'sequelize';
import Article from '../models/Article';
import User from '../models/User';
import Category from '../models/Category';
import Tag from '../models/Tag';
import { redisClient } from '../database';
import { marked } from 'marked';
import DOMPurify from 'dompurify';
import { JSDOM } from 'jsdom';
import slugify from 'slugify';

// 创建DOMPurify实例（用于XSS过滤）
const window = new JSDOM('').window;
const purify = DOMPurify(window);

// 文章查询参数接口
interface ArticleQueryParams {
  page?: number;
  limit?: number;
  status?: 'draft' | 'published' | 'archived';
  category_id?: string;
  tag_id?: string;
  author_id?: string;
  keyword?: string;
  sort_by?: string;
  sort_order?: 'ASC' | 'DESC';
  is_pinned?: boolean;
  is_featured?: boolean;
}

// 文章创建接口
interface ArticleCreateParams {
  title: string;
  content: string;
  summary?: string;
  slug?: string;
  cover_image?: string;
  status: 'draft' | 'published' | 'archived';
  author_id: string;
  category_id?: string;
  tags?: string[];
  meta_title?: string;
  meta_description?: string;
  keywords?: string;
  visibility?: 'public' | 'private';
  password?: string;
  is_pinned?: boolean;
  is_featured?: boolean;
}

// 文章更新接口
interface ArticleUpdateParams extends Partial<ArticleCreateParams> {}

class ArticleService {
  /**
   * 获取文章列表
   * @param params 查询参数
   * @returns 文章列表和总数
   */
  async getArticles(params: ArticleQueryParams) {
    const {
      page = 1,
      limit = 10,
      status,
      category_id,
      tag_id,
      author_id,
      keyword,
      sort_by = 'created_at',
      sort_order = 'DESC',
      is_pinned,
      is_featured,
    } = params;

    const offset = (page - 1) * limit;
    
    // 构建查询条件
    const where: any = {};
    
    if (status) {
      where.status = status;
    }
    
    if (category_id) {
      where.category_id = category_id;
    }
    
    if (author_id) {
      where.author_id = author_id;
    }
    
    if (keyword) {
      where[Op.or] = [
        { title: { [Op.like]: `%${keyword}%` } },
        { content: { [Op.like]: `%${keyword}%` } },
        { summary: { [Op.like]: `%${keyword}%` } },
      ];
    }
    
    if (is_pinned !== undefined) {
      where.is_pinned = is_pinned;
    }
    
    if (is_featured !== undefined) {
      where.is_featured = is_featured;
    }
    
    // 如果有tag_id，需要使用关联查询
    const include: any[] = [
      {
        model: User,
        as: 'author',
        attributes: ['id', 'username', 'nickname', 'avatar'],
      },
      {
        model: Category,
        as: 'category',
        attributes: ['id', 'name', 'slug'],
      },
    ];
    
    if (tag_id) {
      include.push({
        model: Tag,
        as: 'tags',
        attributes: ['id', 'name', 'slug'],
        through: { attributes: [] }, // 不包含中间表字段
        where: { id: tag_id },
      });
    } else {
      include.push({
        model: Tag,
        as: 'tags',
        attributes: ['id', 'name', 'slug'],
        through: { attributes: [] }, // 不包含中间表字段
      });
    }
    
    // 执行查询
    const { rows, count } = await Article.findAndCountAll({
      where,
      include,
      order: [[sort_by, sort_order]],
      limit,
      offset,
      distinct: true, // 避免关联查询导致的计数问题
    });
    
    return {
      articles: rows,
      total: count,
      page,
      limit,
      total_pages: Math.ceil(count / limit),
    };
  }
  
  /**
   * 根据ID获取文章详情
   * @param id 文章ID
   * @param incrementView 是否增加阅读量
   * @returns 文章详情
   */
  async getArticleById(id: string, incrementView = false) {
    // 先尝试从缓存获取
    const cacheKey = `article:${id}`;
    const cachedArticle = await redisClient.get(cacheKey);
    
    if (cachedArticle) {
      const article = JSON.parse(cachedArticle);
      
      // 如果需要增加阅读量，更新数据库和缓存
      if (incrementView) {
        await Article.increment('view_count', { where: { id } });
        article.view_count += 1;
        await redisClient.set(cacheKey, JSON.stringify(article), {
          EX: 3600, // 缓存1小时
        });
      }
      
      return article;
    }
    
    // 缓存未命中，从数据库获取
    const article = await Article.findByPk(id, {
      include: [
        {
          model: User,
          as: 'author',
          attributes: ['id', 'username', 'nickname', 'avatar'],
        },
        {
          model: Category,
          as: 'category',
          attributes: ['id', 'name', 'slug'],
        },
        {
          model: Tag,
          as: 'tags',
          attributes: ['id', 'name', 'slug'],
          through: { attributes: [] },
        },
      ],
    });
    
    if (!article) {
      throw new Error('文章不存在');
    }
    
    // 增加阅读量
    if (incrementView) {
      await article.increment('view_count');
      await article.reload();
    }
    
    // 缓存文章
    await redisClient.set(cacheKey, JSON.stringify(article), {
      EX: 3600, // 缓存1小时
    });
    
    return article;
  }
  
  /**
   * 创建文章
   * @param params 文章参数
   * @returns 创建的文章
   */
  async createArticle(params: ArticleCreateParams) {
    const {
      title,
      content,
      summary,
      slug,
      cover_image,
      status,
      author_id,
      category_id,
      tags = [],
      meta_title,
      meta_description,
      keywords,
      visibility = 'public',
      password,
      is_pinned = false,
      is_featured = false,
    } = params;
    
    // 生成slug（如果未提供）
    const finalSlug = slug || slugify(title, {
      lower: true,
      strict: true,
    });
    
    // 检查slug是否已存在
    const existingArticle = await Article.findOne({
      where: { slug: finalSlug },
    });
    
    if (existingArticle) {
      throw new Error('文章slug已存在，请修改后重试');
    }
    
    // 将Markdown转换为HTML
    const contentHtml = purify.sanitize(marked(content));
    
    // 创建文章
    const article = await Article.create({
      title,
      content,
      content_html: contentHtml,
      summary,
      slug: finalSlug,
      cover_image,
      status,
      author_id,
      category_id,
      meta_title: meta_title || title,
      meta_description: meta_description || summary,
      keywords,
      visibility,
      password,
      is_pinned,
      is_featured,
      published_at: status === 'published' ? new Date() : null,
    });
    
    // 关联标签
    if (tags.length > 0) {
      await article.$set('tags', tags);
      
      // 更新标签的文章计数
      await Tag.increment('article_count', {
        where: { id: { [Op.in]: tags } },
      });
    }
    
    // 如果有分类，更新分类的文章计数
    if (category_id) {
      await Category.increment('article_count', {
        where: { id: category_id },
      });
    }
    
    // 重新加载文章（包含关联数据）
    const createdArticle = await this.getArticleById(article.id);
    
    return createdArticle;
  }
  
  /**
   * 更新文章
   * @param id 文章ID
   * @param params 更新参数
   * @returns 更新后的文章
   */
  async updateArticle(id: string, params: ArticleUpdateParams) {
    const article = await Article.findByPk(id);
    
    if (!article) {
      throw new Error('文章不存在');
    }
    
    const {
      title,
      content,
      summary,
      slug,
      cover_image,
      status,
      category_id,
      tags,
      meta_title,
      meta_description,
      keywords,
      visibility,
      password,
      is_pinned,
      is_featured,
    } = params;
    
    // 检查slug是否已被其他文章使用
    if (slug && slug !== article.slug) {
      const existingArticle = await Article.findOne({
        where: {
          slug,
          id: { [Op.ne]: id },
        },
      });
      
      if (existingArticle) {
        throw new Error('文章slug已存在，请修改后重试');
      }
    }
    
    // 准备更新数据
    const updateData: any = {};
    
    if (title !== undefined) updateData.title = title;
    if (summary !== undefined) updateData.summary = summary;
    if (slug !== undefined) updateData.slug = slug;
    if (cover_image !== undefined) updateData.cover_image = cover_image;
    if (status !== undefined) {
      updateData.status = status;
      
      // 如果状态从非发布变为发布，设置发布时间
      if (status === 'published' && article.status !== 'published') {
        updateData.published_at = new Date();
      }
    }
    if (category_id !== undefined) updateData.category_id = category_id;
    if (meta_title !== undefined) updateData.meta_title = meta_title;
    if (meta_description !== undefined) updateData.meta_description = meta_description;
    if (keywords !== undefined) updateData.keywords = keywords;
    if (visibility !== undefined) updateData.visibility = visibility;
    if (password !== undefined) updateData.password = password;
    if (is_pinned !== undefined) updateData.is_pinned = is_pinned;
    if (is_featured !== undefined) updateData.is_featured = is_featured;
    
    // 如果内容更新，转换为HTML
    if (content !== undefined) {
      updateData.content = content;
      updateData.content_html = purify.sanitize(marked(content));
    }
    
    // 更新文章
    await article.update(updateData);
    
    // 更新标签关联
    if (tags !== undefined) {
      // 获取当前标签
      const currentTags = await article.$get('tags');
      const currentTagIds = currentTags.map((tag: any) => tag.id);
      
      // 设置新标签
      await article.$set('tags', tags);
      
      // 更新标签的文章计数
      const tagsToDecrement = currentTagIds.filter(id => !tags.includes(id));
      const tagsToIncrement = tags.filter(id => !currentTagIds.includes(id));
      
      if (tagsToDecrement.length > 0) {
        await Tag.decrement('article_count', {
          where: { id: { [Op.in]: tagsToDecrement } },
        });
      }
      
      if (tagsToIncrement.length > 0) {
        await Tag.increment('article_count', {
          where: { id: { [Op.in]: tagsToIncrement } },
        });
      }
    }
    
    // 如果分类更改，更新分类的文章计数
    if (category_id !== undefined && category_id !== article.category_id) {
      if (article.category_id) {
        await Category.decrement('article_count', {
          where: { id: article.category_id },
        });
      }
      
      if (category_id) {
        await Category.increment('article_count', {
          where: { id: category_id },
        });
      }
    }
    
    // 清除缓存
    await redisClient.del(`article:${id}`);
    
    // 重新加载文章
    const updatedArticle = await this.getArticleById(id);
    
    return updatedArticle;
  }
  
  /**
   * 删除文章
   * @param id 文章ID
   * @returns 删除结果
   */
  async deleteArticle(id: string) {
    const article = await Article.findByPk(id, {
      include: [
        {
          model: Tag,
          as: 'tags',
          attributes: ['id'],
          through: { attributes: [] },
        },
      ],
    });
    
    if (!article) {
      throw new Error('文章不存在');
    }
    
    // 更新标签的文章计数
    const tags = article.tags || [];
    const tagIds = tags.map((tag: any) => tag.id);
    
    if (tagIds.length > 0) {
      await Tag.decrement('article_count', {
        where: { id: { [Op.in]: tagIds } },
      });
    }
    
    // 如果有分类，更新分类的文章计数
    if (article.category_id) {
      await Category.decrement('article_count', {
        where: { id: article.category_id },
      });
    }
    
    // 删除文章（软删除）
    await article.destroy();
    
    // 清除缓存
    await redisClient.del(`article:${id}`);
    
    return { success: true, message: '文章已删除' };
  }
  
  /**
   * 更改文章状态
   * @param id 文章ID
   * @param status 新状态
   * @returns 更新后的文章
   */
  async changeArticleStatus(id: string, status: 'draft' | 'published' | 'archived') {
    const article = await Article.findByPk(id);
    
    if (!article) {
      throw new Error('文章不存在');
    }
    
    // 如果状态从非发布变为发布，设置发布时间
    const updateData: any = { status };
    if (status === 'published' && article.status !== 'published') {
      updateData.published_at = new Date();
    }
    
    // 更新状态
    await article.update(updateData);
    
    // 清除缓存
    await redisClient.del(`article:${id}`);
    
    // 重新加载文章
    const updatedArticle = await this.getArticleById(id);
    
    return updatedArticle;
  }
}

export default new ArticleService();